Qemu-dm dumps core with the pcnet device. This patches fixes it.
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 2 Sep 2005 17:52:37 +0000 (17:52 +0000)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Fri, 2 Sep 2005 17:52:37 +0000 (17:52 +0000)
When pcnet_receive calls pcnet_poll, which polls the receive and the send
rings. Whenever there is an element in the send ring that is owned by
the Lance chip it will call pcnet_transmit and send it. When the element
is the endp(acket), pcnet_transmit will copy it out, send the packet
(qemu_send_packet) and then clear the owner bit. Somewherer along the
qemu_send_packet execution path, pcnet_recieve is called again, which
calls pcnet_poll and starts this whole process again. This very rapidly
leads to a stack overflow and crashes qemu.

The fix is simple, stop the recursion. Once the packet is copied into
qemu datatstructure (before qemu_send_packet is called!), the owner bit
on the ring element should be cleared.

Signed-Off-By: Leendert van Doorn <leendert@watson.ibm.com>
tools/ioemu/hw/pcnet.c

index 63bd0fad4bc24171db2ecd50a809b061497cadcd..c2a96af636264b60e87312417cabc05730746d07 100644 (file)
@@ -569,6 +569,10 @@ static void pcnet_transmit(PCNetState *s)
             cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr),
                     s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt);
             s->xmit_pos += 4096 - tmd.tmd1.bcnt;
+
+           tmd.tmd1.own = 0;
+           TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+
 #ifdef PCNET_DEBUG
             printf("pcnet_transmit size=%d\n", s->xmit_pos);
 #endif            
@@ -580,10 +584,10 @@ static void pcnet_transmit(PCNetState *s)
             s->csr[0] &= ~0x0008;   /* clear TDMD */
             s->csr[4] |= 0x0004;    /* set TXSTRT */
             s->xmit_pos = -1;
-        }
-
-        tmd.tmd1.own = 0;
-        TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+        } else {
+           tmd.tmd1.own = 0;
+           TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+       }
         if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
             s->csr[0] |= 0x0200;    /* set TINT */